package com.example.demo.controller;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.example.demo.model.entity.DeviceConfig;
import com.example.demo.service.AlarmDeviceConfigService;
import com.example.demo.service.WechatCloudDBService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class OneNetController {

    private static final String TOKEN = "123456";  // 你配置的token
    private static final String AES_KEY = "HV2bxGxGFUjk0rZS";  // 你配置的aesKey

    @Autowired
    private AlarmDeviceConfigService alarmDeviceConfigService;

    @Autowired
    private WechatCloudDBService wechatCloudDBService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * URL验证接口
     */
    @GetMapping("/onenet/push")
    public String validate(@RequestParam String msg,
                           @RequestParam String nonce,
                           @RequestParam String signature) {
        try {
            log.info("收到URL验证请求 - msg: {}, nonce: {}, signature: {}", msg, nonce, signature);

            // 1. 拼接待加密字符串 token + nonce + msg
            String signStr = TOKEN + nonce + msg;

            // 2. 进行md5加密
            byte[] md5Bytes = MessageDigest.getInstance("MD5").digest(signStr.getBytes(StandardCharsets.UTF_8));

            // 3. 将md5结果进行Base64编码
            String calculatedSignature = Base64.getEncoder().encodeToString(md5Bytes);

            // 4. URL解码接收到的signature
            String decodedSignature = URLDecoder.decode(signature, StandardCharsets.UTF_8);

            log.info("计算得到的signature: {}", calculatedSignature);
            log.info("接收到的signature解码后: {}", decodedSignature);

            // 5. 比较signature
            if (decodedSignature.equals(calculatedSignature)) {
                log.info("URL验证通过");
                return msg;
            }

            log.error("URL验证失败");
            return "验证失败";

        } catch (Exception e) {
            log.error("URL验证异常", e);
            return "验证异常";
        }
    }



    /**
     * 数据推送接口
     */
    @PostMapping("/onenet/push")
    public String receive(@RequestBody String body) {
        try {
            log.info("收到OneNET推送原始数据: {}", body);

            // 1. 首先解析外层JSON
            JSONObject receivedJson = JSON.parseObject(body);

            // 2. 获取加密后的消息内容
            String encryptedMsg = receivedJson.getString("msg");
            if (encryptedMsg == null) {
                throw new IllegalArgumentException("Missing required field: msg");
            }

            // 3. 使用加密消息进行去重判断
            String msgKey = "onenet:encrypted:" + DigestUtils.md5DigestAsHex(encryptedMsg.getBytes());
            Boolean setSuccess = redisTemplate.opsForValue()
                    .setIfAbsent(msgKey, "1", 5, TimeUnit.MINUTES);

            if (Boolean.FALSE.equals(setSuccess)) {
                log.info("收到重复消息，msg: {}", encryptedMsg);
                return "ok";
            }

            // 4. 解密消息内容
            String decryptedData = decryptMsg(encryptedMsg);
            log.info("解密后数据: {}", decryptedData);

            // 5. 解析解密后的JSON数据
            JSONObject decryptedJson = JSON.parseObject(decryptedData);
            log.info("解析后的JSON数据: {}", decryptedJson);

            // 6. 处理业务逻辑
            handleOneNetData(decryptedJson);

            return "ok";
        } catch (Exception e) {
            log.error("处理OneNET推送数据异常: {}", e.getMessage(), e);
            return "ok";  // 返回ok避免OneNET重试
        }
    }


    /**
     * AES解密
     */
    private String decryptMsg(String encryptedMsg) throws Exception {
        try {
            // 1. Base64解码
            byte[] encryptedData = Base64.getDecoder().decode(encryptedMsg);

            // 2. 使用AES-CBC-PKCS7Padding模式解密
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            SecretKeySpec keySpec = new SecretKeySpec(AES_KEY.getBytes(StandardCharsets.UTF_8), "AES");
            // 使用AES密钥作为IV
            IvParameterSpec ivSpec = new IvParameterSpec(AES_KEY.getBytes(StandardCharsets.UTF_8));
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

            // 3. 解密数据
            byte[] decryptedData = cipher.doFinal(encryptedData);
            return new String(decryptedData, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("解密数据失败: {}", e.getMessage());
            throw e;
        }
    }


    /**
     * 处理OneNET推送的数据
     */
    private void handleOneNetData(JSONObject data) {
        if (data == null) {
            log.error("数据为空，无法处理");
            return;
        }

        try {
            // 获取消息类型
            String messageType = data.getString("messageType");
            String notifyType = data.getString("notifyType");

            if ("notify".equals(messageType) && "property".equals(notifyType)) {
                handleDeviceProperty(data);
            } else {
                log.info("未处理的消息类型: messageType={}, notifyType={}", messageType, notifyType);
            }
        } catch (Exception e) {
            log.error("处理数据时发生错误: {}", e.getMessage(), e);
        }
    }

    /**
     * 处理设备属性通知
     */
    private void handleDeviceProperty(JSONObject data) {
        try {
            String deviceName = data.getString("deviceName");
            if (deviceName == null) {
                log.warn("设备名称为空");
                return;
            }

            JSONObject params = data.getJSONObject("data")
                    .getJSONObject("params");
            if (params == null) {
                log.warn("属性数据为空");
                return;
            }

            JSONObject sata = params.getJSONObject("sata");
            if (sata == null) {
                log.warn("sata数据为空");
                return;
            }

            String valueStr = sata.getString("value");
            JSONObject valueJson = JSON.parseObject(valueStr);

            // 获取设备状态、电量和信号强度
            String deviceSata = valueJson.getString("device_sata");
            String powerBt = valueJson.getString("power_bt");
            String deviceSignal = valueJson.getString("Device_signal");

            // 处理ICCID更新
            handleIccidUpdate(deviceName, valueJson.getString("Iccid"));

            // 查询设备报警配置
            DeviceConfig deviceConfig = alarmDeviceConfigService.getAlarmConfigByDeviceName(deviceName);

            // 处理不同类型的设备状态
            switch (deviceSata) {
                case "Normal_power_failure":
                    // 电源故障报警，传入电量和信号强度
                    alarmDeviceConfigService.handleDeviceAlarm(deviceName, deviceConfig, "power_failure",
                            powerBt, deviceSignal, deviceSata);
                    break;
                case "Normal":
                    // 更新恢复通知的调用，加入电量和信号信息
                    alarmDeviceConfigService.handleDeviceRecover(deviceName, deviceConfig,
                            powerBt, deviceSignal, deviceSata); 
                    break;
                default:
                    log.info("未处理的设备状态: {}", deviceSata);
            }

            // 记录详细信息
            log.info("设备[{}]状态信息: 信号强度={}, 电池电量={}, 模块型号={}, 版本号={}",
                    deviceName,
                    deviceSignal,
                    powerBt,
                    valueJson.getString("Device_module"),
                    valueJson.getString("Ver"));

        } catch (Exception e) {
            log.error("处理设备属性通知异常: {}", e.getMessage(), e);
        }
    }

    /**
     * 处理ICCID更新
     */
    private void handleIccidUpdate(String deviceName, String iccid) {
        if (deviceName == null || iccid == null) {
            log.warn("设备名称或ICCID为空");
            return;
        }

        try {
            // 1. 首先查询devices集合中是否存在对应的设备
            String whereClause = String.format("{imei: '%s'}", deviceName);
            String queryResult = wechatCloudDBService.query("devices", whereClause);

            // 解析查询结果
            JSONObject queryJson = JSON.parseObject(queryResult);
            if (queryJson.getIntValue("errcode") != 0) {
                log.error("查询设备失败: {}", queryResult);
                return;
            }

            String pdata = queryJson.getString("data");
            if (pdata == null || pdata.equals("[]")) {
                log.info("未找到对应的设备记录: {}", deviceName);
                return;
            }

            // 检查现有记录是否已包含ICCID
            JSONObject deviceData = JSON.parseArray(pdata).getJSONObject(0);
            if (deviceData.containsKey("iccid") && iccid.equals(deviceData.getString("iccid"))) {
                log.info("设备ICCID未发生变化，无需更新");
                return;
            }

            // 2. 更新ICCID
            String updateQuery = String.format(
                    "db.collection('devices').where({imei: '%s'}).update({data: {iccid: '%s'}})",
                    deviceName,
                    iccid
            );

            String updateResult = wechatCloudDBService.executeUpdate(updateQuery);
            JSONObject updateJson = JSON.parseObject(updateResult);

            if (updateJson.getIntValue("errcode") == 0) {
                log.info("成功更新设备[{}]的ICCID: {}", deviceName, iccid);
            } else {
                log.error("更新设备ICCID失败: {}", updateResult);
            }

        } catch (Exception e) {
            log.error("处理ICCID更新异常: {}", e.getMessage(), e);
        }
    }

}
